// ========== Copyright Header Begin ==========================================
// 
// OpenSPARC T1 Processor File: cpu_exec2.cc
// Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// 
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// 
// The above named program is distributed in the hope that it will be 
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// 
// ========== Copyright Header End ============================================
#pragma ident "@(#)1.14	02/07/26	cpu_exec2.cc"
#include "bcore/InstructionEmulator.h"
#include "bcore/cpu_impl.h"
#include "bcore/v9_inst_asm.h"
#include <cassert>
#include "MemoryTransaction.h"
#include "Sf/Sf_Trap.h"
#include "Sf/Sf_Mmu.h"
#include "Util/NumericUtils.h"
#include "StdMacros.h"
#include "Blaze_CBInterface.h"

#include "V9/V9_ArchState.h"
#include "Hv/Hv_ArchState.h"

#define FMT3_RCOND_SHIFT    10

#define SF_ASR_PCR               0x10
#define SF_ASR_PIC               0x11
#define SF_ASR_DCR               0x12
#define SF_ASR_GSR               0x13
#define SF_ASR_SET_SOFTINT       0x14
#define SF_ASR_CLEAR_SOFTINT     0x15
#define SF_ASR_SOFTINT           0x16
#define SF_ASR_TICK_CMPR         0x17
#define SF_ASR_SYSTEM_TICK       0x18
#define SF_ASR_SYSTEM_TICK_CMPR  0x19



/* Macros to pick out the hi and lo Words (unsigned only). */
#ifdef LITTLE_ENDIAN
#define HI_W(lword) (((uint32_t*)&lword)[1])      
#define LO_W(lword) (((uint32_t*)&lword)[0])       
#else
#define HI_W(lword) (((uint32_t*)&lword)[0])      
#define LO_W(lword) (((uint32_t*)&lword)[1])       
#endif

#define SE_IMM13_32(i) (((int )i << 19) >> 19)
#define GET_IU_RS1( rf, instr ) (rf->get(instr.rs1()))
#define GET_IU_RS2( rf, instr ) (instr.i()?instr.simm13():rf->get(instr.rs2()))
#define GET_IU_RS2_MOVCC( rf, instr )(instr.i()?instr.simm11():rf->get(instr.rs2()))
#define GET_IU_RS2_MOVR( rf, instr )(instr.i()?instr.simm10():rf->get(instr.rs2()))
# define CC_FCC0                0x0
# define CC_FCC1                0x1
# define CC_FCC2                0x2
# define CC_FCC3                0x3
# define CC_ICC                 0x4
# define CC_XCC                 0x6
#define ASR_Y    0
#define ASR_CCR  2
#define ASR_ASI  3
#define ASR_TICK 4
#define ASR_PC   5
#define ASR_FPRS 6
#define ASR_SIGM 15
/*  Privledged registers values for RDPR and WRPR. */
#define PR_TPC                 0x0
#define PR_TNPC                0x1
#define PR_TSTATE              0x2
#define PR_TT                  0x3
#define PR_TICK                0x4
#define PR_TBA                 0x5
#define PR_PSTATE              0x6
#define PR_TL                  0x7
#define PR_PIL                 0x8
#define PR_CWP                 0x9
#define PR_CANSAVE             0xa
#define PR_CANRESTORE          0xb
#define PR_CLEANWIN            0xc
#define PR_OTHERWIN            0xd
#define PR_WSTATE              0xe
#define PR_FPQ                 0xf
#define PR_VER                 0x1f
using namespace std;
using namespace Riesling;

#define U(foo) InstructionEmulator::unknown_instr

// Declare here so that I don't have to compile blaze directory for cosim
BlazeCBInterface::BlazeTCCInterceptCB BlazeCBInterface::blazetccinterceptcb_ = NULL;

static uint8_t movfcc_taken[16][4]  =
{

// E  L   G   U

  0,  0,  0,  0, 
  0,  1,  1,  1,
  0,  1,  1,  0,
  0,  1,  0,  1,
  0,  1,  0,  0,
  0,  0,  1,  1,
  0,  0,  1,  0,
  0,  0,  0,  1,

  1,  1,  1,  1,
  1,  0,  0,  0,
  1,  0,  0,  1,
  1,  0,  1,  0,
  1,  0,  1,  1,
  1,  1,  0,  0,
  1,  1,  0,  1,
  1,  1,  1,  0,
};

static uint8_t movcc_taken [16][16]  = 
{

        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
        0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,
        0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,
        0,0,1,1,0,0,1,1,1,1,0,0,1,1,0,0,
        0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,
        0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
        0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,
        0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,
        1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
        1,1,0,0,1,1,0,0,0,0,1,1,0,0,1,1,
        1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,
        1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,
        1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
        1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,
};



int InstructionEmulator::checkTargetPc( const InstructionWord &iw, uint64_t targetPc )
{
    uint_t trapType  = 0;
    uint_t faultType = 0;
    int isVaHole = 0;

    if ((targetPc & 0x3) != 0) {
	trapType = Sf_Trap::mem_address_not_aligned;
	faultType = 0;
	MemoryTransaction xact( targetPc, getDefaultDataAsi(), iw, MemoryTransaction::READ, getStrand() );
	xact.size( 4 );
	mmu_->dMmuTrap( xact, trapType, faultType, NULL );
	return isVaHole;
    } else if ( inVaHole(targetPc) ) {
	isVaHole = 1;
	if( pstate_->getAM() == 0 ) {
	    trapType  = Sf_Trap::instruction_access_exception;
	    faultType = Sf_Mmu::VA_OUT_OF_RANGE_JMPL_RETURN;
	    MemoryTransaction xact( targetPc, getDefaultInstrAsi(), iw, MemoryTransaction::READ, getStrand() );
	    xact.size( 4 );
	    mmu_->iMmuTrap( xact, trapType, faultType, NULL );
	}
    }
    return isVaHole;
}


#if 0
void 
write_softint(cpu_structT*  sp, Word value)
{
       Byte	 irl;
       HWord	 mask;

       sp->softint.w = value & SOFTINT_MASK;
       mask = sp->softint.s.mask << 1;
  	
       /* 
        * If the tick compare interrupt is set, make it look like
        * a normal level 14 interrupt.
	*/
       if (sp->softint.s.tick_int || sp->softint.s.stick_int) {
                mask |= (1 << 14);
       }

       /* Set irl to highest bit set. */
       for(irl = 15; irl > 0; irl--) {
                if (mask & (1 << irl)) {
                        break;
                }
       }

       sp->irl = irl;
       update_async_trap_pending(sp);

}
#endif


int InstructionEmulator::read_asr(uint32_t reg, uint64_t* val) 
{
  switch (reg) {
  case SF_ASR_PCR:
    // Performance Control Register (ASR 16)
//     if (!isPrivMode()) {
//       RIESLING_TRAP( Sf_Trap::privileged_opcode );
//     }
    *val = pcr_->getNative(); 
    break;

  case SF_ASR_PIC:
    // Performance Instrumentation Counter (ASR 17)
    if (!isPrivMode() && pcr_->getPRIV()) {
	RIESLING_TRAP( Sf_Trap::privileged_action );
    }
    *val = pic_->getNative();
    break;

  case SF_ASR_DCR:
    // Dispatch Control Register (ASR 18)
//     if (!isPrivMode()) {
//       RIESLING_TRAP( Sf_Trap::privileged_opcode );
//     }
    *val = dcr_->getNative();
    break;

  case SF_ASR_GSR:
    // Graphics Status Register (ASR 19)
    {
      uint32_t fef = (uint32_t) as_->getFprsRegPtr()->getFEF();
      uint32_t pef = (uint32_t) as_->getPstateRegPtr()->getPEF();
      if ( (fef & pef) == 0 ) {
	RIESLING_TRAP( Sf_Trap::fp_disabled );
      }          
      *val = as_->getGsrRegPtr()->getNative();
      break;
    }

  case SF_ASR_SOFTINT:
    // SOFTINT Register (ASR 22)
//     if (!isPrivMode()) {
//       RIESLING_TRAP( Sf_Trap::privileged_opcode );
//     }
    *val = softint_->getNative();
    break;

  case SF_ASR_TICK_CMPR:
    // Tick Compare Register (ASR 23)
//     if (!isPrivMode()) {
//       RIESLING_TRAP( Sf_Trap::privileged_opcode );
//     }
    *val = tickCompare_->getNative();
    break;

  case SF_ASR_SYSTEM_TICK:
    // System Tick Register (ASR 24)
    if ( (!isPrivMode()) && stick_->getNPT() ) {
      RIESLING_TRAP( Sf_Trap::privileged_action );
    }
    *val = stick_->getNative();
    break;

  case SF_ASR_SYSTEM_TICK_CMPR:
    // System Tick Compare Register (ASR 25)
//     if (!isPrivMode()) {
//       RIESLING_TRAP( Sf_Trap::privileged_opcode );
//     }
    *val = stickCompare_->getNative();
    break;

//   default:
//     RIESLING_TRAP( Sf_Trap::illegal_instruction );
  }

  return 0;
}

int InstructionEmulator::write_asr(uint32_t reg, uint64_t val, InstructionWord &iw, bool checkPrivMode)
{
    // keep in mind that when checkPrivMode==false, iw is NOT valid.
  switch (reg) {
  case SF_ASR_PCR:
    // Performance Control Register (ASR 16)
    if (checkPrivMode) {
// 	if (!isPrivMode()) {
// 	    RIESLING_TRAP( Sf_Trap::privileged_opcode );
// 	}
	// checkPrivMode=false means this write_asr comes from writeAsyncAsrReg
	// which is an explicit pli-socket call, no need to check trap. In such
	// case we should use setNativeHW in order to write into software-read-
	// only, hardware-writable fields.
	checkTrapBeforeCommit(iw); 
	pcr_->setNative( val );
    }
    else {
	pcr_->setNativeHW( val );
    }
    break;

  case SF_ASR_PIC:
    // Performance Instrumentation Counter (ASR 17)
    if (checkPrivMode) {
	if ( (!isPrivMode()) && (pcr_->getPRIV()) ) {
	    RIESLING_TRAP( Sf_Trap::privileged_action );
	}
	checkTrapBeforeCommit(iw);
	pic_->setNative( val );
    }
    else {
	pic_->setNativeHW( val );
    }
    break;

  case SF_ASR_DCR:
    // Dispatch Control Register (ASR 18)
    if (checkPrivMode) {
// 	if (!isPrivMode()) {
// 	    RIESLING_TRAP( Sf_Trap::privileged_opcode );
// 	}
	checkTrapBeforeCommit(iw);
	dcr_->setNative( val );
    }
    else {
	dcr_->setNativeHW( val );
    }
    break;

  case SF_ASR_GSR:
    {
      // Graphics Status Register (ASR 19)
      if (checkPrivMode) {
	  uint32_t fef = (uint32_t) as_->getFprsRegPtr()->getFEF();
	  uint32_t pef = (uint32_t) as_->getPstateRegPtr()->getPEF();
	  if ( (fef & pef) == 0 ) {
	      RIESLING_TRAP( Sf_Trap::fp_disabled );
	  }          
	  checkTrapBeforeCommit(iw);
	  as_->getGsrRegPtr()->setNative( val );
      }
      else {
	  as_->getGsrRegPtr()->setNativeHW( val );
      }
    }
    break;

  case SF_ASR_SET_SOFTINT:
    // Set softint (ASR 20)
    // A Write State Register instruction (WRSOFTINT_SET) to ASR 20 
    // sets the corresponding bits in the SOFTINT Register (ASR 22), 
    // that is, when set, bits 16:0 in ASR 20 set the corresponding bits 
    // in ASR 22. Other bits in ASR 20 are ignored. ASR 20 is a privileged, 
    // write-only register. 
    if (checkPrivMode) {
// 	if (!isPrivMode()) {
// 	    RIESLING_TRAP( Sf_Trap::privileged_opcode );
// 	}
	checkTrapBeforeCommit(iw);
	softint_->setNative( softint_->getNative() | val );
    }
    else {
	softint_->setNativeHW( softint_->getNative() | val );
    }
    break;

  case SF_ASR_CLEAR_SOFTINT:
    // Clear softint (ASR 21)
    // A Write State Register instruction (WRSOFTINT_CLR) to ASR 21 clears 
    // the corresponding bits in the SOFTINT register(ASR 22);
    // that is, when set, bits 16:0 in ASR 21 clear the corresponding bits 
    // in ASR 22. Other bits in ASR 21 are ignored.
    if (checkPrivMode) {
// 	if (!isPrivMode()) {
// 	    RIESLING_TRAP( Sf_Trap::privileged_opcode );
// 	}
	checkTrapBeforeCommit(iw);
	softint_->setNative( softint_->getNative() & ~val );
    }
    else {
	softint_->setNativeHW( softint_->getNative() & ~val );
    }
    break;

  case SF_ASR_SOFTINT:
    // SOFTINT Register (ASR 22)
    if (checkPrivMode) {
// 	if (!isPrivMode()) {
// 	    RIESLING_TRAP( Sf_Trap::privileged_opcode );
// 	}
	checkTrapBeforeCommit(iw);
	softint_->setNative( val );
    }
    else {
	softint_->setNativeHW( val );
    }
    break;

  case SF_ASR_TICK_CMPR:
    // Tick Compare Register (ASR 23)
    if (checkPrivMode) {
// 	if (!isPrivMode()) {
// 	    RIESLING_TRAP( Sf_Trap::privileged_opcode );
// 	}
	checkTrapBeforeCommit(iw);
	tickCompare_->setNative( val );
    }
    else {
	tickCompare_->setNativeHW( val );
    }
    break;

  case SF_ASR_SYSTEM_TICK:
    // System Tick Register (ASR 24)
    if (checkPrivMode) {
// 	if (!isPrivMode()) {
// 	    RIESLING_TRAP( Sf_Trap::privileged_opcode );
// 	}
	checkTrapBeforeCommit(iw);
	stick_->setNative( val );
    }
    else {
	stick_->setNativeHW( val );
    }
    break;

  case SF_ASR_SYSTEM_TICK_CMPR:
    // System Tick Compare Register (ASR 25)
    if (checkPrivMode) {
// 	if (!isPrivMode()) {
// 	    RIESLING_TRAP( Sf_Trap::privileged_opcode );
// 	}
	checkTrapBeforeCommit(iw);
	stickCompare_->setNative( val );
    }
    else {
	stickCompare_->setNativeHW( val );
    }
    break;

  default:
      if (checkPrivMode) {
// 	  RIESLING_TRAP( Sf_Trap::illegal_instruction );
      }
      else {
	  cerr << "ERROR: InstructionEmulator::write_asr: ASR 0x" << hex << reg << " is not supported by asr_write pli-socket command\n";
      }
  }

  return 0;
}

#if 0

#define BAD_WIN_REG_VALUE(Win)      (Win % sp->nwins)
#define BAD_WIN_REG_VALUE_P(Win, p) (Win % p->nwins)

/*
 * The instruction OP field indexes this array and selects the exec routine.
 */
#define	U(_x)	depricated_op

void depricated_op(cpu_structT* sp, uint32_t iw)
{
	fprintf(stderr,"Internal error : Op2 instr 0x%llx : 0x%x\n", sp->pc, iw);
	assert(0);
}

/* Called for unknown op2 instruction. */
void unknown_fcpu_op2_instr(cpu_structT* sp, uint32_t iw)
{
     RIESLING_TRAP( Sf_Trap::illegal_instruction );
}
#endif

void (InstructionEmulator::*InstructionEmulator::exec_op2_routines[])( InstructionWord& ) = {

        U(&InstructionEmulator::exec_add), U(&InstructionEmulator::exec_and), U(&InstructionEmulator::exec_or), U(&InstructionEmulator::exec_xor),
        U(&InstructionEmulator::exec_sub), U(&InstructionEmulator::exec_andn), U(&InstructionEmulator::exec_orn), U(&InstructionEmulator::exec_xnor),
	&InstructionEmulator::exec_addc, &InstructionEmulator::exec_mulx, U(exec_umul), U(exec_smul),
	&InstructionEmulator::exec_subc, &InstructionEmulator::exec_udivx, &InstructionEmulator::exec_udiv, &InstructionEmulator::exec_sdiv,

	&InstructionEmulator::exec_addcc, U(&InstructionEmulator::exec_andcc), U(&InstructionEmulator::exec_orcc), &InstructionEmulator::exec_xorcc,
        U(&InstructionEmulator::exec_subcc), &InstructionEmulator::exec_andncc, &InstructionEmulator::exec_orncc, &InstructionEmulator::exec_xnorcc,
	&InstructionEmulator::exec_addccc, &InstructionEmulator::unknown_fcpu_op2_instr, &InstructionEmulator::exec_umulcc, &InstructionEmulator::exec_smulcc,
	&InstructionEmulator::exec_subccc, &InstructionEmulator::unknown_fcpu_op2_instr, &InstructionEmulator::exec_udivcc, &InstructionEmulator::exec_sdivcc,

	&InstructionEmulator::exec_taddcc, &InstructionEmulator::exec_tsubcc, &InstructionEmulator::exec_taddcctv, &InstructionEmulator::exec_tsubcctv,
	&InstructionEmulator::exec_mulscc, U(&InstructionEmulator::exec_sll), U(&InstructionEmulator::exec_srl), &InstructionEmulator::exec_sra,
	&InstructionEmulator::exec_rdasr, &InstructionEmulator::unknown_fcpu_op2_instr, &InstructionEmulator::exec_rdpr, &InstructionEmulator::exec_flushw,
	//        exec_movcc_wrapper, exec_sdivx, exec_popc, exec_movr_wrapper,
	&InstructionEmulator::exec_movcc, &InstructionEmulator::exec_sdivx, &InstructionEmulator::exec_popc, &InstructionEmulator::exec_movr_wrapper,

	&InstructionEmulator::exec_wrasr, U(&InstructionEmulator::exec_saved), &InstructionEmulator::exec_wrpr, &InstructionEmulator::unknown_fcpu_op2_instr,
	&InstructionEmulator::fpop_wrapper, &InstructionEmulator::fpop_wrapper, &InstructionEmulator::gop_wrapper, &InstructionEmulator::unknown_fcpu_op2_instr,
	&InstructionEmulator::exec_jmpl, &InstructionEmulator::exec_return, &InstructionEmulator::exec_tcc, &InstructionEmulator::exec_flush,
	&InstructionEmulator::exec_save, &InstructionEmulator::exec_restore, &InstructionEmulator::exec_retry, &InstructionEmulator::unknown_fcpu_op2_instr
};

	/*
	 * An enumeration table for the op3 values for op==2
	 */

typedef enum {
    /* Col 0  (0x00 - 0x0f) */
        Op2_add, Op2_and, Op2_or, Op2_xor,
        Op2_sub, Op2_andn, Op2_orn, Op2_xnor,
        Op2_addc, Op2_mulx, Op2_umul, Op2_smul,
        Op2_subc, Op2_udivx, Op2_udiv, Op2_sdiv,
    /* Col 1  (0x10 - 0x1f) */
        Op2_addcc, Op2_andcc, Op2_orcc, Op2_xorcc,
        Op2_subcc, Op2_andncc, Op2_orncc, Op2_xnorcc,
        Op2_addccc, Op2_unknown_0x19, Op2_umulcc, Op2_smulcc,
        Op2_subccc, Op2_unknown_0x1d, Op2_udivcc, Op2_sdivcc,
    /* Col 2  (0x20 - 0x2f) */
        Op2_taddcc, Op2_tsubcc, Op2_taddcctv, Op2_tsubcctv,
        Op2_mulscc, Op2_sll, Op2_srl, Op2_sra,
        Op2_rdasr, Op2_unknown_0x29, Op2_rdpr, Op2_flushw,
        Op2_movcc, Op2_sdivx, Op2_popc, Op2_movr,
    /* Col 3  (0x30 - 0x3f) */
        Op2_wrasr, Op2_saved, Op2_wrpr, Op2_unknown_0x33,
        Op2_fpop_0x34, Op2_fpop_0x35, Op2_gop, Op2_unknown_0x37,
        Op2_jmpl, Op2_return, Op2_tcc, Op2_flush,
        Op2_save, Op2_restore, Op2_retry, Op2_unknown_0x3f
} op2_code_t;

bool
InstructionEmulator::exec_op2( InstructionWord &i )
{
	(this->*exec_op2_routines[i.op3()])( i );
	if(instrAccepted_){
	    return true;
	}
	return false;
}

#define EXEC_FUNC(_fn)	void InstructionEmulator::exec_##_fn( InstructionWord &i ) {
#define	END_FUNC(_fn)	}	/* _fn */


EXEC_FUNC(addc)
	uint32_t	rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );

	uint64_t wr = addx_instr( r1, r2, P_ICC_C);
        checkTrapBeforeCommit(i);
	if (rd != 0)
	{
	    ireg_->set( rd, wr );
	}
END_FUNC(addc)


EXEC_FUNC( mulx )
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

	mulx_instr(&r1,&r2,&wr);
        checkTrapBeforeCommit(i);
	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}

END_FUNC( mulx )


EXEC_FUNC(subc)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

	wr = subx_instr(r1,r2,P_ICC_C);
        checkTrapBeforeCommit(i);
	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}
END_FUNC( subc )


EXEC_FUNC( udivx )
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

	if (HI_W(r2) == 0 && LO_W(r2) == 0) {
	    RIESLING_TRAP( Sf_Trap::division_by_zero );
	    return;
	}

	udivx_instr(&r1,&r2,&wr);
        checkTrapBeforeCommit(i);
	if (rd != 0) {
            ireg_->set( rd, wr );
	}
END_FUNC( udivx )


EXEC_FUNC( udiv )
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

       	if (LO_W(r2) == 0) {
	    RIESLING_TRAP( Sf_Trap::division_by_zero );
	}
        udiv_asm(LO_W(r1), LO_W(r2), &wr, y_->getY());
        checkTrapBeforeCommit(i);
	if (rd != 0) {
            ireg_->set( rd, wr );
	}
END_FUNC( udiv )


EXEC_FUNC( sdiv )
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

       	if(LO_W(r2) == 0) {
	    RIESLING_TRAP( Sf_Trap::division_by_zero );
	    return;
	}
        sdiv_asm(LO_W(r1), LO_W(r2), &wr, y_->getY() );
        checkTrapBeforeCommit(i);
	if (rd != 0) {
            ireg_->set( rd, wr );
	}
END_FUNC( sdiv )


EXEC_FUNC( addcc )
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

    
	uint8_t ccr_b = ccr_->getByte();
	addcc_instr(&r1, &r2, &wr, &ccr_b);
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );
	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}
END_FUNC( addcc )


EXEC_FUNC(xorcc)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

	uint8_t ccr_b = ccr_->getByte();
	xorcc_instr(&r1, &r2, &wr, &ccr_b );
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );

	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}
END_FUNC(xorcc)

EXEC_FUNC(andncc)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

	uint8_t ccr_b = ccr_->getByte();
	andncc_instr(&r1, &r2, &wr, &ccr_b );
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );

	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}
END_FUNC(andncc)



EXEC_FUNC( orncc )
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

    
	uint8_t ccr_b = ccr_->getByte();
	orncc_instr(&r1, &r2, &wr, &ccr_b);
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );

	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}
END_FUNC(orncc)

EXEC_FUNC(xnorcc)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

    
	uint8_t ccr_b = ccr_->getByte();
	xnorcc_instr(&r1, &r2, &wr, &ccr_b);
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );
	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}
END_FUNC(xnorcc)

EXEC_FUNC(addccc)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

    
	uint8_t ccr_b = ccr_->getByte();
	addxcc_instr(&r1, &r2, &wr, (uint8_t*)&ccr_b);
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );
	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}
END_FUNC(addccc)

EXEC_FUNC(umulcc)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

    
	uint8_t ccr_b = ccr_->getByte();
	uint32_t y = 0;
	umulcc_asm( LO_W(r1), LO_W(r2), &wr, &ccr_b, &y );
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );
	y_->setY(y);

	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}
END_FUNC(umulcc)


EXEC_FUNC(smulcc)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

    
	uint8_t ccr_b = ccr_->getByte();
	unsigned y = 0;
	smulcc_asm( LO_W(r1), LO_W(r2), &wr, &ccr_b, &y );
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );
	y_->setY(y);

	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}
END_FUNC(smulcc)

EXEC_FUNC(subccc)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

    
	uint8_t ccr_b = ccr_->getByte();
	subxcc_instr(&r1, &r2, &wr, &ccr_b);
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );
	if (rd != 0)
	{
            ireg_->set( rd, wr );
	}
END_FUNC(subccc)

EXEC_FUNC(udivcc)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

        if(LO_W(r2) == 0) {
	    RIESLING_TRAP( Sf_Trap::division_by_zero );
	    return;
	}

	uint8_t ccr_b = ccr_->getByte();
	uint32_t y = y_->getY();
        udivcc_asm(LO_W(r1), LO_W(r2), &wr, &ccr_b, y);
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );
	y_->setY(y);

	if (rd != 0) {
            ireg_->set( rd, wr );
	}
END_FUNC(udivcc)


EXEC_FUNC(sdivcc)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

        if(LO_W(r2) == 0) {
	    RIESLING_TRAP( Sf_Trap::division_by_zero );
	    return;
	}

	uint8_t ccr_b = ccr_->getByte();
	uint32_t y = y_->getY();
        sdivcc_asm(LO_W(r1), LO_W(r2), &wr, &ccr_b, y );
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr_b );
	y_->setY(y);

	if (rd != 0) {
            ireg_->set( rd, wr );
	}
END_FUNC(sdivcc)

EXEC_FUNC(taddcc)
	uint32_t	rd = i.rd();
	uint64_t   	wr; 		
	uint64_t	r1;		
	uint64_t	r2;		
	uint8_t         ccr;

        r1 = GET_IU_RS1 ( ireg_, i );
        r2 = GET_IU_RS2 ( ireg_, i );

	taddcc_instr(&r1, &r2, &wr, &ccr);
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr );
	if (rd != 0)
	{
	  ireg_->set(rd, wr);
	}
END_FUNC(taddcc)


EXEC_FUNC(tsubcc)
	uint32_t	rd = i.rd();
	uint64_t   	wr; 		
	uint64_t	r1;		
	uint64_t	r2;		
	uint8_t         ccr;

        r1 = GET_IU_RS1 ( ireg_, i );
        r2 = GET_IU_RS2 ( ireg_, i );

	tsubcc_instr(&r1, &r2, &wr, &ccr);
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr );
	if (rd != 0)
	{
	  ireg_->set(rd, wr);
	}
END_FUNC(tsubcc)

EXEC_FUNC(taddcctv)
	uint32_t	rd = i.rd();
	uint64_t   	wr; 		
	uint64_t	r1;		
	uint64_t	r2;		
	uint8_t         ccr;
	V9_CcrReg       tmpCcrReg;

        r1 = GET_IU_RS1 ( ireg_, i );
        r2 = GET_IU_RS2 ( ireg_, i );

	taddcc_instr(&r1, &r2, &wr, &ccr);
	tmpCcrReg.setByte(ccr);
	if (tmpCcrReg.getIV()) {
	    RIESLING_TRAP( Sf_Trap::tag_overflow );
	}
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr );
	if (rd != 0)
	{
	  ireg_->set(rd, wr);
	}
END_FUNC(taddcctv)

EXEC_FUNC(tsubcctv)
	uint32_t	rd = i.rd();
	uint64_t   	wr; 		
	uint64_t	r1;		
	uint64_t	r2;		
	uint8_t         ccr;
	V9_CcrReg       tmpCcrReg;

        r1 = GET_IU_RS1 ( ireg_, i );
        r2 = GET_IU_RS2 ( ireg_, i );

	tsubcc_instr(&r1, &r2, &wr, &ccr);
	tmpCcrReg.setByte(ccr);
	if (tmpCcrReg.getIV()) {
	    RIESLING_TRAP( Sf_Trap::tag_overflow );
	}
        checkTrapBeforeCommit(i);
	ccr_->setByte( ccr );
	if (rd != 0)
	{
	  ireg_->set(rd, wr);
	}
END_FUNC(tsubcctv)

uint32_t 
InstructionEmulator::getMulsccUndefinedHiWord( uint32_t rs1HiWord )
{
    return rs1HiWord;
}

EXEC_FUNC(mulscc)
   	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

    
	uint8_t ccr = ccr_->getByte();
	uint32_t y    = y_->getY();
	uint64_t Rtmp1, Rtmp2, Rtmp3;
	uint64_t xcc_n, xcc_z, xcc_v, xcc_c;

#define BIT63( value )  (value & (1ULL << 63))
#define BIT( pos )  ( 1ULL << pos )

#define MPSAS_CCR_IV( value ) (( value >> 1 ) & 0x1)
#define MPSAS_CCR_IN( value ) (( value >> 3 ) & 0x1)

	Rtmp1 = 0;
	LO_W(Rtmp1) = LO_W(r1) >> 1;

	HI_W(Rtmp1)  = getMulsccUndefinedHiWord( HI_W(r1) );
	LO_W(Rtmp1) &= ~BIT(31);		// Clear bit 31
	LO_W(Rtmp1) |= ( (MPSAS_CCR_IN( ccr ) ^ MPSAS_CCR_IV( ccr )) << 31 );

	Rtmp2 = (y & 0x1) ? r2 : 0;

	wr = Rtmp1 + Rtmp2;
	y = ((LO_W(r1) & 0x1) << 31) | ((y >> 1) & ~BIT(31));

        checkTrapBeforeCommit(i);
	setAddCC( wr, Rtmp1, Rtmp2 );
	y_->setY( y );

	ireg_->set( rd, wr );
END_FUNC(mulscc)


EXEC_FUNC(sra)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		
	uint64_t Wtmp;

	if ( i.x() == 1) {
	    Wtmp = LO_W(r2) & 0x3f;
	    srax_instr(&r1, Wtmp, &wr);
	} else {
	    Wtmp = LO_W(r2) & 0x1f;
	    wr = sra_instr(r1, Wtmp);
	}
        checkTrapBeforeCommit(i);
	if (rd != 0)
	{
	    ireg_->set( rd, wr );
	}
END_FUNC(sra)


#define MEMBAR_CMASK_SYNC_MASK  0x4   

EXEC_FUNC(rdasr)
	uint32_t rd = i.rd();
	uint32_t Wtmp = i.rs1();
        uint64_t r1 = ireg_->get( Wtmp );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		
	int	 ret = 0;

// 	if (i.i() == 1 && Wtmp != ASR_SIGM) {
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	}

	switch (Wtmp) {
	case ASR_Y:
		wr = y_->getNative();
		break;
	case ASR_CCR:
		wr = ccr_->getNative();
		break;
	case ASR_ASI:
		wr = asi_->getNative();
		break;
	case ASR_TICK:
		if ( (!isPrivMode()) && tick_->getNPT() ) {
		    RIESLING_TRAP( Sf_Trap::privileged_action );
		}
		wr = tick_->getNative();
		break;
	case ASR_PC:
		wr = as_->getPc();
		break;
	case ASR_FPRS:
		wr = fprs_->getNative();
		break;
// 	case 1:	/* Reserved */
// 	case 7:	/* Reserved */
// 	case 8:	/* Reserved */
// 	case 9:	/* Reserved */
// 	case 10:/* Reserved */
// 	case 11:/* Reserved */
// 	case 12:/* Reserved */
// 	case 13:/* Reserved */
// 	case 14:/* Reserved */
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 		return;

	case ASR_SIGM:
		switch (rd) {
		case 0:
			// TODO  MEMBAR and STBAR
			// TODO check that i==1
		    if ((i.cmask() & MEMBAR_CMASK_SYNC_MASK) == MEMBAR_CMASK_SYNC_MASK) {
			// stxa to mmu will be committed for data accesses only
			// TODO review the effect on itlb mmu registers
			mmu_->commitDataAsiWrites();
		    }
		    break;
// 		default:
// 		    RIESLING_TRAP( Sf_Trap::illegal_instruction );
		}
		break;
	default:
		ret = read_asr( Wtmp, &wr);
		break;
	}

        checkTrapBeforeCommit(i);
	if (ret == 0) {
		if (rd != 0) {
		    ireg_->set( rd, wr );
		}
	}
	return;
END_FUNC(rdasr)


EXEC_FUNC( rdpr )
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

// 	if (!isPrivMode()) {
// 	    RIESLING_TRAP( Sf_Trap::privileged_opcode );
// 	}

	switch (i.rs1()) {
	case PR_TPC:
// 	    if (tl_->getTL() == 0) {
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 		return;
// 	    }
	    wr = tpc_->getTpc( tl_->getTL() );
	    break;
	case PR_TNPC:
// 	    if (tl_->getTL() == 0) {
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 		return;
// 	    }
	    wr = tnpc_->getTnpc( tl_->getTL() );
	    break;
	case PR_TSTATE:
	{
// 	    if (tl_->getTL() == 0) {
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 		return;
// 	    }

	    const V9_TstateEntry &tstateEntry = tstate_->getTstateEntry( tl_->getTL() );
	    wr = tstateEntry.getNative();
	    break;
	}
	case PR_TT:
// 	    if ( tl_->getTL() == 0) {
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 		return;
// 	    }
	    wr = trapType_->getTrapType( tl_->getTL() ) & 0x01ff;
	    break;
	case PR_TICK:
	    wr = tick_->getNative();
	    break;
	case PR_TBA:
	    wr = tba_->getNative();
	    break;
	case PR_PSTATE:
	    wr = pstate_->getNative();
	    break;
	case PR_TL:
	    wr = tl_->getTL();
	    break;
	case PR_PIL:
	    wr = pil_->getTL();
	    break;
	case PR_CWP:
	    wr = ireg_->getCWP();
	    break;
	case PR_CANSAVE:
	    wr = ireg_->getCANSAVE();
	    break;
	case PR_CANRESTORE:
	    wr = ireg_->getCANRESTORE();
	    break;
	case PR_CLEANWIN:
	    wr = ireg_->getCLEANWIN();
	    break;
	case PR_OTHERWIN:
	    wr = ireg_->getOTHERWIN();
	    break;
	case PR_WSTATE:
	    wr = wstate_->getNative();
	    break;
// 	case PR_FPQ:
// 	    RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	    return;
	case PR_VER:
	    wr = version_->getNative();
	    break;
// 	default:
// 	    RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	    return;
	}

        checkTrapBeforeCommit(i);
        if (rd != 0) {
	    ireg_->set( rd, wr );
        }
	return;
END_FUNC(rdpr)


#define SF_T_SPILL_NORMAL_BASE   0x80
#define SF_T_SPILL_OTHER_BASE    0xA0
#define SF_T_FILL_NORMAL_BASE    0xC0
#define SF_T_FILL_OTHER_BASE     0xE0


EXEC_FUNC(flushw)
	uint64_t  trap_type;


//         if ( i.i() == 1 ) {
// 	    RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	}

	if ( ireg_->flushw() ) {
	    if (ireg_->getOTHERWIN() == 0) {
		trap_type = SF_T_SPILL_NORMAL_BASE + (wstate_->getNORMAL() << 2);
	    } else {
		trap_type = SF_T_SPILL_OTHER_BASE + (wstate_->getOTHER() << 2);
	    }
	    RIESLING_TRAP ( trap_type );
	    return;
	}

        checkTrapBeforeCommit(i);
END_FUNC(flushw)

//////////////////////////////

void InstructionEmulator::exec_movcc ( InstructionWord &i )
{
        uint64_t r2 = GET_IU_RS2_MOVCC ( ireg_, i );
	uint32_t rd = i.rd();
        uint8_t  cc = i.movCC();
        uint32_t cc_val;         

	unsigned cond = i.get( 17, 14 );
	switch( cc ){
	    case CC_FCC0:
	    case CC_FCC1:
	    case CC_FCC2:
	    case CC_FCC3:
		checkTrapBeforeCommit(i);
		instrAccepted_ = false;
		break;

	    case CC_ICC:
		checkTrapBeforeCommit(i);
		cc_val = GET_ICC( ccr_ );
		if (movcc_taken[cond][cc_val]) {
		    ireg_->set( rd, r2 );
		}
		break;
	    case CC_XCC:
		checkTrapBeforeCommit(i);
		cc_val = GET_XCC( ccr_ );
		if (movcc_taken[cond][cc_val]) {
		    ireg_->set( rd, r2 );
		}
		break;
// 	    default:
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 		break;
	}
}
 
//////////////////////////////

EXEC_FUNC(sdivx)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		

	if (HI_W(r2) == 0 && LO_W(r2) == 0) {
	    RIESLING_TRAP( Sf_Trap::division_by_zero );
	}
	sdivx_instr(&r1,&r2,&wr);
        checkTrapBeforeCommit(i);
	if (rd != 0) {
	    ireg_->set( rd, wr );
	}
END_FUNC(sdivx)

EXEC_FUNC(popc)
    //////////////////////////////////////////////////
    // POPC is not implemented in MPSAS
//     RIESLING_TRAP( Sf_Trap::illegal_instruction );

    // illegal_instruction if instr[18:14] != 0
//     if( i.getNative() >> 14 & 0x01f != 0 ){
// 	RIESLING_TRAP( Sf_Trap::illegal_instruction );
//     }

    uint32_t rd = i.rd();
    uint64_t r2Val = GET_IU_RS2( ireg_, i );
    uint_t count = 0;
    while( r2Val != 0 ){
	if( r2Val & 0x01ULL ){ ++count; }
	r2Val >>= 1;
    }	

    checkTrapBeforeCommit(i);
    ireg_->set( rd, count );
END_FUNC(popc)


/* NOTE: stack is not executable in v9 */
uint32_t movr_asm[3] = {
	0x90102000, /* mov 0, %o0 */
	0x81c3e008, /* retl */
	0x917a6001 /* movrcc %o1, 1, %o0 */
};

#define FMT3_IMM10_SEX64(value)  ((int64_t)(((int32_t)value << 22) >> 22))


#define MOVRZ    1
#define MOVRLEZ  2
#define MOVRLZ   3
#define MOVRNZ   5
#define MOVRGZ   6
#define MOVRGEZ  7


void InstructionEmulator::exec_movr( InstructionWord &iw )
{
        uint32_t	rd = iw.rd();
	uint64_t   	wr; 		
	uint64_t	r1;		
	uint64_t	r2;		
	uint32_t	Wtmp;

	movr_asm[2] = 0x917a6001;

        r1 = GET_IU_RS1( ireg_, iw );
        r2 = GET_IU_RS2_MOVR( ireg_, iw );

	switch ( iw.rcond() ) {

        case MOVRZ:
	case MOVRLEZ:
	case MOVRLZ:
	case MOVRNZ:
	case MOVRGZ:
	case MOVRGEZ:
		Wtmp = iw.rcond() << FMT3_RCOND_SHIFT;
		movr_asm[2] = movr_asm[2] | Wtmp;
		iflush((caddr_t)&movr_asm[2]);
		if (iw.i()) 
			r2 = FMT3_IMM10_SEX64(r2);
		movr_instr(movr_asm, &r1, &r2, &wr, &rd);
		break;

// 	default:
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 		return;
	}

        checkTrapBeforeCommit(iw);
	if (rd != 0) {
	  ireg_->set(rd, wr);
	}
}

void InstructionEmulator::exec_movr_wrapper( InstructionWord &iw )
{
#if 0
	extern mutex_t asm_lock;

	mutex_lock(&asm_lock);
	exec_movr(sp, iw);
	mutex_unlock(&asm_lock);
#endif

	exec_movr(iw);
}


EXEC_FUNC(wrasr)
	uint32_t rd = i.rd();
        uint64_t r1 = ireg_->get( i.rs1() );
        uint64_t r2 = GET_IU_RS2( ireg_, i );
	uint64_t wr; 		
	uint64_t		Rtmp = r1 ^ r2;
	uint32_t		Wtmp;
	uint32_t		Wtmp2;
	int	        	ret = 0;


	switch (rd) {
	    case ASR_Y:
		checkTrapBeforeCommit(i);
		y_->setNative( Rtmp );
		break;
	    case ASR_CCR:
		checkTrapBeforeCommit(i);
		ccr_->setNative( Rtmp );
		break;
	    case ASR_ASI:
		checkTrapBeforeCommit(i);
		asi_->setNative( Rtmp );
		break;
	    case ASR_FPRS:
		checkTrapBeforeCommit(i);
		fprs_->setNative( Rtmp );
		break;

// 	    case 1:	/* Reserved */
// 	    case 4:	/* Reserved */
// 	    case 5:	/* Reserved */
// 	    case 7:	/* Reserved */
// 	    case 8:	/* Reserved */
// 	    case 9:	/* Reserved */
// 	    case 10:    /* Reserved */
// 	    case 11:    /* Reserved */
// 	    case 12:    /* Reserved */
// 	    case 13:    /* Reserved */
// 	    case 14:    /* Reserved */
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 		return;

	    case ASR_SIGM:
// 		    Wtmp  = i.rs1(); /*RS1 has to be zero */
// 		    Wtmp2 = i.i();   /* i has to be 1 */
// 		    if(Wtmp || !Wtmp2)  {
// 			RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 			return;
// 		    }

		    /* If privileged, cause reset trap. */
		    if (isPrivMode()) {
			RIESLING_TRAP( Sf_Trap::software_initiated_reset );
			return;
		    }

		    /* Otherwise, ignore instruction (NOP). */
		    checkTrapBeforeCommit(i);
		    break;
	    default:
		    ret = write_asr(rd, Rtmp, i);
		    break;
	}
END_FUNC(wrasr)

void InstructionEmulator::exec_SAVED (InstructionWord &i)
{
    if ( isPrivMode() ){
	checkTrapBeforeCommit(i);
	ireg_->saved();
    } 
//     else {
// 	RIESLING_TRAP( Sf_Trap::privileged_opcode );
//     }
}

void InstructionEmulator::exec_RESTORED (InstructionWord &i)
{
    if ( isPrivMode() ){
        checkTrapBeforeCommit(i);
	ireg_->restored();
    } 
//     else {
// 	RIESLING_TRAP( Sf_Trap::privileged_opcode );
//     }
}

EXEC_FUNC(wrpr)
    uint32_t	rd = i.rd();
    uint64_t	Rtmp;
    uint32_t	Wtmp;
    int		ret = 0;


//     if (!isPrivMode()) {
// 	RIESLING_TRAP( Sf_Trap::privileged_opcode );
//     }

    Rtmp = ireg_->get( i.rs1() ) ^ GET_IU_RS2 ( ireg_, i );

    switch (rd) {
    case PR_TPC:
// 	    if (tl_->getTL() == 0) {
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	    }
	    checkTrapBeforeCommit(i);
	    tpc_->setTpc( tl_->getTL(), (Rtmp & ~0x03ULL) );
	    break;
    case PR_TNPC:
// 	    if (tl_->getTL() == 0) {
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	    }

	    PRINT_DEBUG( "Trap level = %d\n", (tl_->getTL()) );
	    checkTrapBeforeCommit(i);
	    tnpc_->setTnpc( tl_->getTL(), (Rtmp & ~0x03ULL) );
	    break;
    case PR_TSTATE:
    {
// 	    if (tl_->getTL() == 0) {
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 		return;
// 	    }

            V9_TstateEntry tstateEntry = tstate_->getTstateEntry( tl_->getTL() );
	    tstateEntry.setNative( Rtmp );
	    checkTrapBeforeCommit(i);
	    tstate_->setTstateEntry( tl_->getTL(), tstateEntry );
	    break;
    }
    break;
    case PR_TT:
// 	    if (tl_->getTL() == 0) {
// 		RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	    }
	    checkTrapBeforeCommit(i);
	    trapType_->setTrapType( tl_->getTL(), Rtmp & 0x01ffULL );
	    break;
    case PR_TICK:
            checkTrapBeforeCommit(i);
	    tick_->setNative( Rtmp );
	    break;
    case PR_TBA:
            checkTrapBeforeCommit(i);
	    tba_->setNative( Rtmp );
	    break;
    case PR_PSTATE: 
	    {
		V9_PstateReg tmpPstate( *pstate_ );
		tmpPstate.setNative( Rtmp );

	      /* Make sure only one global bit is set. */
		//TODO  move to InstructionWord checking
	      if ( tmpPstate.getAG() + tmpPstate.getMG() + tmpPstate.getIG() > 1) {
	          RIESLING_TRAP( Sf_Trap::illegal_instruction );
	      }
	      checkTrapBeforeCommit(i);
	      pstate_->setNative( Rtmp );
	      updatePstate( *pstate_ );

	      // TODO verify this function call after implementing traps/interrupts
	      // update_async_trap_pending(sp);

	    }
	    break;
    case PR_TL:
            checkTrapBeforeCommit(i);
	    if (LO_W(Rtmp) > getMaxTrapLevel() ) {
		tl_->setTL( getMaxTrapLevel() );
	    } else {
		tl_->setTL( LO_W(Rtmp) );
	    }
	    break;
	    
    case PR_PIL:
            checkTrapBeforeCommit(i);
	    pil_->setTL( LO_W(Rtmp) & interruptLevelMask() );
	    // TODO verify this function call after implementing traps/interrupts
	    // update_async_trap_pending(sp);
	    break;
    case PR_CWP:
            checkTrapBeforeCommit(i);
	    ireg_->setCWP( Rtmp );
	    break;
    case PR_CANSAVE:
            checkTrapBeforeCommit(i);
	    ireg_->setCANSAVE( Rtmp );
	    break;
    case PR_CANRESTORE:
            checkTrapBeforeCommit(i);
	    ireg_->setCANRESTORE( Rtmp );
	    break;
    case PR_CLEANWIN:
            checkTrapBeforeCommit(i);
	    ireg_->setCLEANWIN( Rtmp );
	    break;
    case PR_OTHERWIN:
            checkTrapBeforeCommit(i);
	    ireg_->setOTHERWIN( Rtmp );
	    break;
    case PR_WSTATE:
            checkTrapBeforeCommit(i);
	    wstate_->setNative( Rtmp );
	    break;
//     default:
// 	    RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	    return;
    }
END_FUNC(wrpr)

bool InstructionEmulator::exec_JMPL_rd15 ( InstructionWord &i )
{

    // TODO  Blaze assumes that immediate bit is 0, which is not
    //       clear from Sparc V9 manual. Therefore using GET_IU_RS2
    //       to be on the safe side.

    VaddrT target = ireg_->get(i.rs1()) + GET_IU_RS2( ireg_, i );

    checkTargetPc( i, target );

    // checkTrapBeforeCommit(i);

    ctiTaken_ = true;
    
    if (!pstate_tct_enabled_)
    {
        ctiExec_  = true;
	ireg_->set( i.rd(), as_->getPc() );
        as_->setPc( as_->getNpc() );
        as_->setNpc( target );
    }
    return true;
}


EXEC_FUNC(jmpl)
    uint64_t	Rtmp;

    Rtmp = ireg_->get( i.rs1() ) + GET_IU_RS2 ( ireg_, i );

    checkTargetPc( i, Rtmp );
    
    checkTrapBeforeCommit(i);

    ctiTaken_ = true;
    
    if (!pstate_tct_enabled_)
    {
        ctiExec_  = true;
        ireg_->set( i.rd(), as_->getPc() );
        as_->setPc( as_->getNpc() );
        as_->setNpc( Rtmp );
    }
END_FUNC(jmpl)


EXEC_FUNC( return )
    uint64_t	Rtmp = ireg_->get( i.rs1() ) + GET_IU_RS2( ireg_, i );
    uint64_t    trap_type;

    if ( ireg_->getCANRESTORE() == 0 ) {
        if (ireg_->getOTHERWIN() == 0) {
	    trap_type = SF_T_FILL_NORMAL_BASE + (wstate_->getNORMAL() << 2);
	} else {
	    trap_type = SF_T_FILL_OTHER_BASE + (wstate_->getOTHER() << 2);
	}
	RIESLING_TRAP ( trap_type );
	return;
    }

    checkTargetPc( i, Rtmp );

    checkTrapBeforeCommit(i);

    ctiTaken_ = true;
    
    if (!pstate_tct_enabled_)
    {
        if (!ireg_->restore()) {
            RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
        }

        ctiExec_  = true;
        as_->setPc( as_->getNpc() );
        as_->setNpc( Rtmp);
    }
END_FUNC( return)

EXEC_FUNC(tcc)
        uint32_t	rd = i.rd();
	uint64_t	r1;		
	uint64_t	r2;		
        uint8_t         cc_val;
       
        r1 = ireg_->get( i.rs1() );
        r2 = GET_IU_RS2( ireg_, i );

        if( i.trapCC() == 0 ){ // icc
	    cc_val = ccr_->getICodes();
        } else if( i.trapCC() == 2 ){ // xcc
	    cc_val = ccr_->getXCodes();
        } 
//         else {
// 	    RIESLING_TRAP( Sf_Trap::illegal_instruction );
//         }

        checkTrapBeforeCommit(i);

	if (movcc_taken[i.cond()][cc_val]) 
        {
	    uint32_t  trap_num;
	    const uint32_t TRAP_MASK = 0x07f;

	    if( i.i() ){
	        // sw trap number is least significant 7 bits of r[rs1] + sw_trap_#
	        trap_num = ( r1 + i.swTrapNr() ) & TRAP_MASK;
	    } else {
	        // sw trap number is least significant 7 bits of r[rs1] + r[rs2]
	        trap_num = ( r1 + ireg_->get( i.rs2() ) ) & TRAP_MASK;
	    }
		
	    // TODO: why wasn't 256 added to this before?
	    // TODO need to make sure there are no higher priority interrupts
	    // where to do this is TBD
	    
            trap_num += 0x100; 

	    if (BlazeCBInterface::getblazetccinterceptcb()) {
	      uint64_t rr = 0;
	      int in;
	      if ((*BlazeCBInterface::getblazetccinterceptcb())(trap_num,
								&rr, &in))
		return;
	    }

            ctiTaken_ = true;
            if (!pstate_tct_enabled_)
            {
	        ctiExec_ = true;
	        RIESLING_TRAP( trap_num );
            }
	    return;
	} 
        else 
        {
	    ctiExec_ = true;
	    // as_->setPc( as_->getNpc() );
	    // as_->setNpc( as_->getNpc() + 4 );
	    as_->incrPcs();
	}
END_FUNC(tcc)

#define TRAP_NONE 0

EXEC_FUNC(flush)
    // TODO flush is NOP for now
    uint64_t  vaddr;
    uint64_t  paddr;

    checkTrapBeforeCommit(i);

    vaddr = ireg_->get(i.rs1()) + GET_IU_RS2( ireg_, i );

// TODO IO address space check

    vaddr &= ~0x4;
    vaddr &= ~0x3; // TODO software is not supposed to set the lower 2 bits
    MemoryTransaction readXact( vaddr, getDefaultDataAsi(), i, MemoryTransaction::READ, getStrand() );
    readXact.size( 8 );
    mmu_->handleData( readXact );
    paddr = readXact.paddr();

    // stxa to mmu will be committed only after a FLUSH, DONE, or RETRY
    mmu_->commitAllAsiWrites();
    return;
#if 0
	uint64_t   	wr; 	
	uint64_t	r1;	
	uint64_t	r2;	
	uint64_t	Rtmp;
        uint64_t        paddr;
        int             ret;

        r1 = GET_IU_RS1 (sp, iw);
        r2 = GET_IU_RS2 (sp, iw);
	Rtmp = r1 + r2;
        ret = ifetch_trap_annulled (sp, Rtmp, &paddr);
	if (ret != TRAP_NONE) {
		paddr = 0;
	}
#endif
END_FUNC(flush)

EXEC_FUNC( save )
    uint32_t rd = i.rd();
    uint64_t r1 = ireg_->get( i.rs1() );
    uint64_t r2 = GET_IU_RS2( ireg_, i );
    uint32_t trap_type;
    uint64_t value;

    if ( ireg_->getCANSAVE() == 0 ) {

        if (ireg_->getOTHERWIN() == 0) {
	    trap_type = SF_T_SPILL_NORMAL_BASE + (wstate_->getNORMAL() << 2);
	} else {
	    trap_type = SF_T_SPILL_OTHER_BASE + (wstate_->getOTHER() << 2);
	}
	RIESLING_TRAP ( trap_type );
	return;
    }

    if ( ireg_->getCLEANWIN() == ireg_->getCANRESTORE() ) {
	RIESLING_TRAP( Sf_Trap::clean_window );
	return;
    }

    // ireg_->save() will update registers' value, must check breakpoint
    // before it happens.
    checkTrapBeforeCommit(i);

    if( !ireg_->save() ){
	RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
    }

    if (rd != 0) {
	ireg_->set( rd, r1 + r2 );
    }
END_FUNC(save)


EXEC_FUNC(restore)
    uint32_t rd = i.rd();
    uint64_t r1 = ireg_->get( i.rs1() );
    uint64_t r2 = GET_IU_RS2( ireg_, i );
    uint64_t trap_type;

    if ( ireg_->getCANRESTORE() == 0 ) {
        if (ireg_->getOTHERWIN() == 0) {
	    trap_type = SF_T_FILL_NORMAL_BASE + (wstate_->getNORMAL() << 2);
	} else {
	    trap_type = SF_T_FILL_OTHER_BASE + (wstate_->getOTHER() << 2);
	}
	RIESLING_TRAP ( trap_type );
	return;
    }

    // ireg_->restore() will update registers' value, must check breakpoint
    // before it happens.
    checkTrapBeforeCommit(i);

    if( !ireg_->restore() ){
	RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
    }

    if (rd != 0) {
	ireg_->set( rd, r1 + r2 );
    }

    
END_FUNC(restore)

EXEC_FUNC(retry)
    uint32_t	rd = i.rd();

//     if (!isPrivMode()) {
// 	RIESLING_TRAP( Sf_Trap::privileged_opcode );
// 	return;
//     }

//     if (tl_->getTL() == 0 || rd > 1) {
// 	RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 	return;
//     }

    checkTrapBeforeCommit(i);

    ctiTaken_ = true;

    if (!pstate_tct_enabled_)
    {
        ctiExec_  = true;
    
        if (rd == 0) {
	  //            as_->setPc( tnpc_->getTnpc( tl_->getTL() ) );
	  //            as_->setNpc( tnpc_->getTnpc( tl_->getTL() ) + 4 );
	  as_->setPcs( tnpc_->getTnpc( tl_->getTL() ) );
        } else if (rd == 1) {
            as_->setPc( tpc_->getTpc( tl_->getTL() ) );
            as_->setNpc( tnpc_->getTnpc( tl_->getTL() ) );
        }
        
        V9_TstateEntry& e = tstate_->getTstateEntry( tl_->getTL() );
        
        ccr_->setNative( e.getCcr() ); 
        asi_->setNative( e.getAsi() );
        ireg_->setCWP( e.getCwp() );
        pstate_->setNative( e.getPstate() );
        updatePstate( *pstate_ );
    
        // TODO verify this function call after implementing traps/interrupts
        // update_async_trap_pending(sp);
    
        // stxa to MMU will be committed only after FLUSH, DONE, or RETRY
        mmu_->commitAllAsiWrites();
    
        tl_->setTL( tl_->getTL() - 1 );
    }
END_FUNC(retry)

void InstructionEmulator::unknown_fcpu_op2_instr( InstructionWord &i )
{
     RIESLING_TRAP( Sf_Trap::illegal_instruction );
}

void InstructionEmulator::fpop_wrapper( InstructionWord &i )
{
    RIESLING_THROW_DOMAIN_ERROR( "Unimplemented" );
}

void InstructionEmulator::gop_wrapper( InstructionWord &i )
{
    RIESLING_THROW_DOMAIN_ERROR( "Unimplemented" );
}



void InstructionEmulator::setAddCC( uint64_t rdVal, uint64_t rs1Val, uint64_t rs2Val )
{
    uint_t bit31_rd  = NumericUtils::getBits( rdVal,  31, 31 );
    uint_t bit31_rs1 = NumericUtils::getBits( rs1Val, 31, 31 );
    uint_t bit31_rs2 = NumericUtils::getBits( rs2Val, 31, 31 );

    ccr_->setIN( bit31_rd );
    ccr_->setIZ( NumericUtils::getLoWord( rdVal ) == 0 );
    ccr_->setIV( (bit31_rs1 && bit31_rs2 && !bit31_rd) ||
		 (!bit31_rs1 && !bit31_rs2 && bit31_rd ) );
    ccr_->setIC( (bit31_rs1 && bit31_rs2) || 
		 (!bit31_rd && (bit31_rs1 || bit31_rs2)) );

    uint_t bit63_rd  = NumericUtils::getBits( rdVal,  63, 63 );
    uint_t bit63_rs1 = NumericUtils::getBits( rs1Val, 63, 63 );
    uint_t bit63_rs2 = NumericUtils::getBits( rs2Val, 63, 63 );

    ccr_->setXN( bit63_rd );
    ccr_->setXZ( rdVal == 0 );
    ccr_->setXV( (bit63_rs1 && bit63_rs2 && !bit63_rd) ||
		 (!bit63_rs1 && !bit63_rs2 && bit63_rd ) );
    ccr_->setXC( (bit63_rs1 && bit63_rs2) || 
		 (!bit63_rd && (bit63_rs1 || bit63_rs2)) );

}
